package com.huahua.graduateschoolspringboot.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.InetSocketAddress;

@Slf4j
@Component
public class NettyServerRun {


    private final EventLoopGroup bossGroup = new NioEventLoopGroup();
    private final EventLoopGroup workGroup = new NioEventLoopGroup();
    private static Channel channel;

    public ChannelFuture start(InetSocketAddress socketAddress) throws Exception {

        ChannelFuture future = null;

        ServerBootstrap bootstrap = new ServerBootstrap()
                //第1步  定义两个线程组，用来处理客户端通道的accept和读写事件
                //bossGroup用来处理accept事件，workGroup用来处理通道的读写事件
                //bossGroup获取客户端连接，连接接收到之后再将连接转发给workGroup去处理
                .group(bossGroup, workGroup)
                // 第2步  绑定服务端通道
                .channel(NioServerSocketChannel.class)
                // 第3步  处理读写事件，ChannelInitializer是给通道初始化
                .childHandler(new NettyServerInitializer())
                .localAddress(socketAddress)
                /**
                 * 设置队列大小
                 * 用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。
                 * 用来初始化服务端可连接队列
                 * 服务端处理客户端连接请求是按顺序处理的，所以同一时间只能处理一个客户端连接，多个客户端来的时候，服务端将不能处理的客户端连接请求放在队列中等待处理
                 */
                .option(ChannelOption.SO_BACKLOG, 1024);
        // 两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文
//				.childOption(ChannelOption.SO_KEEPALIVE, true);
        // 绑定端口,开始接收进来的连接
        try {
            future = bootstrap.bind(socketAddress).sync();

            channel = future.channel();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (future != null && future.isSuccess()) {
                log.info(">>>>>> Netty 服务端启动成功，IP：" + socketAddress.getAddress() + "，端口：" + socketAddress.getPort() + " ...");
            } else {
                log.error(">>>>> Netty 服务端启动失败!");
            }
        }
        return future;
    }

    @PreDestroy
    /**
     * 停止服务
     */
    public void destroy() {
        if (channel != null) {
            channel.close();
            workGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
            log.info("Netty 服务端关闭!");
        }
    }
}
